<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>深浅拷贝</title>
</head>

<body>
    <script>
        // 浅拷贝
        // 1.object.assign()
        var obj = { a: 1, b: { c: 2 } };
        var arr = [1, 2, { val: 4 }]
        var obj1 = {};
        Object.assign(obj1, obj);
        // obj1.b.c = 3;
        // console.log(obj, obj1);

        // 2. ...扩展运算符
        var obj2 = { ...obj };
        // obj2.b.c = 4;
        // console.log(obj, obj2);

        // 3. array.concat
        var arr1 = arr.concat();
        // console.log(arr1);

        // 4. array.slice
        var arr2 = arr.slice();
        // arr2[2].val = 100
        // console.log(arr2);

        // 手写浅拷贝
        function shallowClone(target) {
            if (typeof target === 'object' && target !== null) {
                var cloneTarget = Array.isArray(target) ? [] : {}
                for (let prop in target) {
                    if (target.hasOwnProperty(prop)) {
                        cloneTarget[prop] = target[prop]
                    }
                }
                return cloneTarget
            } else {
                return target
            }
        }
        var obj3 = shallowClone(obj);
        // console.log(obj3);

        // 深拷贝  普通版，遍历拷贝对象的key值，如果是对象就递归调用方法；否则直接赋值
        function deepClone(target) {
            var cloneObj = {}
            for (const prop in target) {
                if (target.hasOwnProperty(prop)) {
                    if (typeof target[prop] === 'object') {
                        cloneObj[prop] = deepClone(target[prop])
                    } else {
                        cloneObj[prop] = target[prop]
                    }
                }
            }
            return cloneObj
        }

        // 完整版
        // 针对不可枚举属性和symbol类型，使用reflect.ownkeys方法；
        // 针对Date、Regexp类型，直接生成新的实例返回；
        const isComplexDataType = obj => (typeof obj === 'object' || typeof obj === 'function') && (obj !== null)
        function deepClone1(obj, hash = new WeakMap()) {
            if (obj.constructor === Date) {
                return new Date(obj);
            }
            if (obj.constructor === RegExp) {
                return new RegExp(obj)
            }

            if (hash.has(obj)) {
                return hash.get(obj)
            }

            let allDesc = Object.getOwnPropertyDescriptor(obj)

            let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc)

            hash.set(obj, cloneObj);

            for (let key of Reflect.ownKeys(obj)) {
                cloneObj[key] = (isComplexDataType(obj[key]) && typeof obj[key] !== 'function') ? deepClone(obj[key], hash) : obj[key]
            }

            return cloneObj;
        }


    </script>
</body>

</html>